#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "EtPeManager.h"

#include "Class.h"
#include "ProgEnv.h"
#include "ObjectTable.h"
#include "PathLookup.h"
#include "OrdColl.h"
#include "System.h"
#include "ImageItem.h"
#include "Window.h"
#include "Buttons.h"
#include "BorderItems.h"
#include "Env.h"
#include "Box.h"
#include "String.h"

#include "Inspector.h"
#include "ClassTree.h"
#include "ClassManager.h"
#include "OStruBrowser.h"
#include "SrcBrowser.h"
#include "EtPeCmdNo.h"
#include "MethodAccessor.h"
#include "Reference.h"

extern Manager *gApplication;

#include "pe_icon.xpm3"
#include "pe_src.xpm3"
#include "pe_insp.xpm3"
#include "pe_ostru.xpm3"
#include "pe_hier.xpm3"

static SmartBitmap IconBm(pe_icon), SrcBm(pe_src), InspBm(pe_insp),
				OStruBm(pe_ostru), HierarchyBm(pe_hier);

EtPeManager *gEtPeManager;

//---- EtPeManager -------------------------------------------------------------

NewMetaImpl0(EtPeManager, Dialog);

PathLookup *EtPeManager::universe;

EtPeManager::EtPeManager() : Dialog("ET++PE", eWinFixed)
{
	wtype= eWinStandard;
	SetOnDismiss(eMgrIconize);
	if (Env::GetValue("ProgEnv.UseMapFiles", TRUE))
		methodAccessor= new PeMapMethodAccessor();
	else
		methodAccessor= new PeScanMethodAccessor();
}

EtPeManager::~EtPeManager()
{
	SafeDelete(methodAccessor);
}

VObject *EtPeManager::DoMakeContent()
{
	return
		new HExpander(gPoint4,
			new ActionButton(cIdNewInsp,     new ImageItem(InspBm)),
			new ActionButton(cIdNewOBrowser, new ImageItem(OStruBm)),
			new ActionButton(cIdNewBrowser,  new ImageItem(SrcBm)),
			new ActionButton(cIdNewHier,     new ImageItem(HierarchyBm)),
			0
		);
}

void EtPeManager::Control(int id, int what, void *val)
{
	switch (id) {
	case cIdNewInsp:
		PeInspector::ShowObject(this, gApplication, FALSE);
		break;
	case cIdNewHier:
		PeHierarchyBrowser::ShowClass(this, gClassManager->Find("Object"));
		break;
	case cIdNewOBrowser:
		PeObjectBrowser::ShowObject(this, gApplication);
		break;
	case cIdNewBrowser:
		PeSourceBrowser::ShowClass(this, gApplication->IsA(), TRUE);
		break;
	case 12345:
		Hide();
		return;
	}

	switch (what) {

	case cPeNewInsp:
		PeInspector::ShowObject(this, gApplication, FALSE);
		break;
	case cPeShowInspector:
		PeInspector::ShowObject(this, (Object*)val, FALSE);
		break;
	case cPeSpawnInsp:
		PeInspector::Spawn(this, (Ref*)val, FALSE);
		break;

	case cPeNewHier:
		PeHierarchyBrowser::ShowClass(this, gClassManager->Find("Object"));
		break;
	case cPeSpawnHier:
		PeHierarchyBrowser::Spawn(this, (Class*)val);
		break;
	case cPeShowHierarchy:
		PeHierarchyBrowser::ShowClass(this, (Class*)val);
		break;
		
	case cPeNewOBrowser:
		PeObjectBrowser::ShowObject(this, gApplication);
		break;
	case cPeSpawnOBrowser:
		PeObjectBrowser::Spawn(this, (Object*)val);
		break;
	case cPeShowOBrowser:
		PeObjectBrowser::ShowObject(this, (Object*)val);
		break;
		
	case cPeSpawnBrowser:
		PeSourceBrowser::Spawn(this, (Class*)val, TRUE);
		break;
	case cPeShowBrowser:
		PeSourceBrowser::ShowClass(this, (Class*)val, TRUE);
		break;
	}
	if (id < cIdFirstUser)
		Dialog::Control(id, what, val);
}

VObject *EtPeManager::DoMakeIconContent()
{
	return new ImageItem(IconBm);
}

PathLookup *EtPeManager::Universe()
{
	if (universe == 0)
		universe= new PathLookup(Symbol("ProgEnv.SrcPath"));
	return universe;
}

bool EtPeManager::FileOfClass(Class *cl, char *fname, bool decl)
{
	const char *path, *base, *bp;
	fname[0]= '\0';
	if (decl)
		base= cl->GetDeclFileName();
	else
		base= cl->GetImplFileName();
	path= "" /* cl->GetCompDir() */;
	if (base[0] != '/') {
		strcpy(fname, path);
		strcat(fname, "/");
	}
	if (base[0] == '.' && base[1] == '/') {
		bp= &base[2];
		strcat(fname, bp);
	} else {
		bp= base;
		strcat(fname,base);
	}
	if (gSystem->AccessPathName(fname, 4) != 0) {
		PathLookup *pl= gEtPeManager->Universe();
		if (! pl->Lookup(bp, fname))
			return FALSE;
	}
	return TRUE;
}

void EtPeManager::CollectParts(Collection*)
{
	// empty: suppress display of ETPE objects
}

Collection *EtPeManager::LoadMethodsOfClass(Class *cl)
{
	Collection *methods= cl->GetMethods();
	if (methods == 0 && methodAccessor) {
		if (universe == 0)
			universe= Universe();
		methods= methodAccessor->FindMethods(cl, universe);
		if (methods && methods->IsKindOf(OrdCollection))
			Guard(methods, OrdCollection)->Sort();
		cl->SetMethods(methods);
	}
	return methods;
}

bool EtPeManager::SameMethods(const char *m1, const char *m2)
{
	return (strcmp(m1, m2) == 0);
}

bool EtPeManager::IsDestructor(const char *m1)
{
	return m1[0] == '~';
}

Command *EtPeManager::DoMenuCommand(int cmd)
{
	if (cmd < cUSERCMD)
		return Dialog::DoMenuCommand(cmd);
	return gNoChanges;
}

//---- MethodReference ---------------------------------------------------------

NewMetaImpl(PeMethodReference, ByteArray, (TP(clp), T(line), TB(isPublic)));

PeMethodReference::PeMethodReference(int l, Class *c, const char *method,
											bool ip) : ByteArray((byte*)method)
{
	clp= c;
	line= l;
	isPublic= ip;
}

bool PeMethodReference::IsEqual(Object *op)
{
	if (op == 0 || !op->IsKindOf(PeMethodReference))
		return FALSE;
	PeMethodReference *mrp= (PeMethodReference *)op;
	return (strcmp((char*)Str(), (char*)mrp->Str()) == 0) && (clp == mrp->clp);
}

